#ifndef SEMINIX_STRING_HELPERS_H
#define SEMINIX_STRING_HELPERS_H

#include <seminix/string.h>
#include <seminix/types.h>
#include <seminix/ctype.h>

/* Descriptions of the types of units to
 * print in */
enum string_size_units {
    STRING_UNITS_10,	/* use powers of 10^3 (standard SI) */
    STRING_UNITS_2,		/* use binary powers of 2^10 */
};

void string_get_size(u64 size, u64 blk_size, enum string_size_units units,
             char *buf, int len);

#define UNESCAPE_SPACE		0x01
#define UNESCAPE_OCTAL		0x02
#define UNESCAPE_HEX		0x04
#define UNESCAPE_SPECIAL	0x08
#define UNESCAPE_ANY		\
    (UNESCAPE_SPACE | UNESCAPE_OCTAL | UNESCAPE_HEX | UNESCAPE_SPECIAL)

int string_unescape(char *src, char *dst, usize size, unsigned int flags);

static inline int string_unescape_inplace(char *buf, unsigned int flags)
{
    return string_unescape(buf, buf, 0, flags);
}

static inline int string_unescape_any(char *src, char *dst, usize size)
{
    return string_unescape(src, dst, size, UNESCAPE_ANY);
}

static inline int string_unescape_any_inplace(char *buf)
{
    return string_unescape_any(buf, buf, 0);
}

#define ESCAPE_SPACE		0x01
#define ESCAPE_SPECIAL		0x02
#define ESCAPE_NULL		0x04
#define ESCAPE_OCTAL		0x08
#define ESCAPE_ANY		\
    (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL)
#define ESCAPE_NP		0x10
#define ESCAPE_ANY_NP		(ESCAPE_ANY | ESCAPE_NP)
#define ESCAPE_HEX		0x20

int string_escape_mem(const char *src, usize isz, char *dst, usize osz,
        unsigned int flags, const char *only);

static inline int string_escape_mem_any_np(const char *src, usize isz,
        char *dst, usize osz, const char *only)
{
    return string_escape_mem(src, isz, dst, osz, ESCAPE_ANY_NP, only);
}

static inline int string_escape_str(const char *src, char *dst, usize sz,
        unsigned int flags, const char *only)
{
    return string_escape_mem(src, strlen(src), dst, sz, flags, only);
}

static inline int string_escape_str_any_np(const char *src, char *dst,
        usize sz, const char *only)
{
    return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, only);
}

static inline void string_upper(char *dst, const char *src)
{
    do {
        *dst++ = toupper(*src);
    } while (*src++);
}

static inline void string_lower(char *dst, const char *src)
{
    do {
        *dst++ = tolower(*src);
    } while (*src++);
}

unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base);
long simple_strtol(const char *cp, char **endp, unsigned int base);
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
long long simple_strtoll(const char *cp, char **endp, unsigned int base);

char *put_dec(char *buf, unsigned long long n);

int num_to_str(char *buf, int size, unsigned long long num, int width);

extern char *skip_spaces(const char *);

extern char *strim(char *);

static inline char *strstrip(char *str)
{
    return strim(str);
}

int match_string(const char * const *array, usize n, const char *string);

char *strreplace(char *s, char old, char new);

/**
 * strstarts - does @str start with @prefix?
 * @str: string to examine
 * @prefix: prefix to look for.
 */
static inline bool strstarts(const char *str, const char *prefix)
{
    return strncmp(str, prefix, strlen(prefix)) == 0;
}

/**
 * kbasename - return the last part of a pathname.
 *
 * @path: path to extract the filename from.
 */
static inline const char *kbasename(const char *path)
{
    const char *tail = strrchr(path, '/');
    return tail ? tail + 1 : path;
}

/**
 * str_has_prefix - Test if a string has a given prefix
 * @str: The string to test
 * @prefix: The string to see if @str starts with
 *
 * A common way to test a prefix of a string is to do:
 *  strncmp(str, prefix, sizeof(prefix) - 1)
 *
 * But this can lead to bugs due to typos, or if prefix is a pointer
 * and not a constant. Instead use str_has_prefix().
 *
 * Returns: 0 if @str does not start with @prefix
         strlen(@prefix) if @str does start with @prefix
 */
static __always_inline usize str_has_prefix(const char *str, const char *prefix)
{
    usize len = strlen(prefix);
    return strncmp(str, prefix, len) == 0 ? len : 0;
}

#endif /* !SEMINIX_STRING_HELPERS_H */
